package org.zcl.distributeLock;

import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @Package org.zcl.distributeLock
 * @PROJECT_NAME: question
 * @DESCRIPTION:
 * @USER: zhuchenglin
 * @DATE: 2022/5/31 19:22
 */
public class WatchCallBack implements Watcher, AsyncCallback.StringCallback, AsyncCallback.Children2Callback, AsyncCallback.StatCallback {

    ZooKeeper zk;
    String threadName;
    CountDownLatch cc = new CountDownLatch(1);

    public String getPathName() {
        return pathName;
    }

    public void setPathName(String pathName) {
        this.pathName = pathName;
    }

    String pathName;


    public String getThreadName() {
        return threadName;
    }

    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }


    public ZooKeeper getZk() {
        return zk;
    }

    public void setZk(ZooKeeper zk) {
        this.zk = zk;
    }

    public void tryLock() {
        try {
            zk.create("/lock", threadName.getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, this, "abc");
            cc.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void unLock() {
        try {
            zk.delete(pathName, -1);
            System.out.println(threadName + ": unlock");
        } catch (InterruptedException | KeeperException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void process(WatchedEvent watchedEvent) {
        switch (watchedEvent.getType()) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                // 节点删除，他后一个节点重新获得list，判断自己是不是第一个获得锁(只有删除后面的一个节点监控删除的节点，其他不监控)
                zk.getChildren("/", false, this, "child");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
            case DataWatchRemoved:
                break;
            case ChildWatchRemoved:
                break;
            case PersistentWatchRemoved:
                break;
        }

    }

    @Override
    public void processResult(int rc, String path, Object ctx, String name) {
        // 创建节点回调
        if (StringUtils.isNotEmpty(name)) {
            System.out.println(threadName + "-create node：" + name);
            pathName = name;
            // 看是不是目录下最小的，只关注前面一个节点不需要监控其他子节点的事件
            zk.getChildren("/", false, this, "child");
        }
    }

    @Override
    public void processResult(int rc, String path, Object ctx, List<String> list, Stat stat) {
        // getChildren回调，此时可以看到前面的节点

        // 获取排序
        Collections.sort(list);
        // 是不是第一个，是就继续执行，不是继续找
        int i = list.indexOf(pathName.substring(1));
        if (i == 0) {
            System.out.println(threadName + ":i am first");
            try {
                // 节点操作过快，事件已经跑完，后面的节点来不及监控
                zk.setData("/", threadName.getBytes(StandardCharsets.UTF_8), -1);
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
            // 获取锁成功，继续执行
            cc.countDown();
        } else {
            // 其他判断前面节点在不在，如果前面节点删除了再去判断自己是不是最小一个然后获取锁
            zk.exists("/" + list.get(i - 1), this, this, "sdf");
        }
    }

    @Override
    public void processResult(int tc, String path, Object ctx, Stat stat) {
        // zk.getChildren("/", false, this, "child");
    }
}
